package com.itmgg.web.websocket;

import com.google.gson.Gson;
import com.itmgg.web.utils.WebSocketUtils;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.yeauty.annotation.*;
import org.yeauty.pojo.Session;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Component
@ServerEndpoint(host = "${ws.host}", port = "${ws.port}", path = "/ws/{arg}", childOptionSoKeepalive = "${ws.childOptionSoKeepalive}")
public class WebSocketServer {
    // 保存连接已连接对象（map键值对的保存方式）
    // 第一个key对应流程实例id 第二个key为用户id以及时间戳
    private static Map<String,Map<String, Session>> sessionPool = new HashMap<>();

    private Session session;

    @BeforeHandshake
    public void handshake(Session session, HttpHeaders headers, @RequestParam String req, @RequestParam MultiValueMap reqMap, @PathVariable String arg, @PathVariable Map pathMap) {
        session.setSubprotocols("stomp");
//        if (!"ok".equals(req)) {
//            log.info("Authentication failed!");
//            session.close();
//        }
    }

    @OnOpen
    public void onOpen(Session session, HttpHeaders headers, @RequestParam String req, @RequestParam MultiValueMap reqMap, @PathVariable String arg, @PathVariable Map pathMap) {
        SocketIns socketIns = WebSocketUtils.buildSession(reqMap, session);
        log.info("new connection===================================socketIns={}", new Gson().toJson(socketIns));
        this.session = session;
        if (MapUtils.isNotEmpty(sessionPool) && sessionPool.containsKey(socketIns.getInstanceId())) { // map不为空 且 当前实例流程id存在
            Map<String, Session> sessionMap = sessionPool.get(socketIns.getInstanceId()); // 获取当前实例下的用户预览Map
            if (MapUtils.isEmpty(sessionMap)) {
                sessionMap = new HashMap<>();
                sessionMap.put(socketIns.getSocketId(), session);
            }else {
                sessionMap.put(socketIns.getSocketId(), session);
            }
        }else {
            Map<String, Session> map = new HashMap<>();
            map.put(socketIns.getSocketId(), session);
            sessionPool.put(socketIns.getInstanceId(), map);
        }
    }

    @OnClose
    public void onClose(Session session) throws IOException {
        log.info("onClose===========================================================");
        SocketIns socketIns = session.getAttribute("socketIns");
        log.info("socketIns=========================={}", socketIns);
        Map<String, Session> sessionMap = sessionPool.get(socketIns.getInstanceId()); // 获取流程实例下的用户sessionMap
        if (MapUtils.isNotEmpty(sessionMap) && sessionMap.containsKey(socketIns.getSocketId())) { // 用户seesionMap不为空 并且包含id
            // 删除该key
            sessionMap.remove(socketIns.getSocketId());
        }
        if (MapUtils.isEmpty(sessionMap)) { // 如果删除完后 用户sessionMap为空 则删除流程实例key
            sessionPool.remove(socketIns.getInstanceId());
        }
        log.info("one connection closed=============================socketId={}", socketIns.getSocketId());
    }

    @OnError
    public void onError(Session session, Throwable throwable) {
        throwable.printStackTrace();
    }

    @OnMessage
    public void onMessage(Session session, String message) {
        log.info(message);
        session.sendText("Hello Netty!");
    }

    @OnBinary
    public void onBinary(Session session, byte[] bytes) {
        for (byte b : bytes) {
            log.info("==================================");
        }
        session.sendBinary(bytes);
    }

    @OnEvent
    public void onEvent(Session session, Object evt) {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
            switch (idleStateEvent.state()) {
                case READER_IDLE:
                    log.info("read idle");
                    break;
                case WRITER_IDLE:
                    log.info("write idle");
                    break;
                case ALL_IDLE:
                    log.info("all idle");
                    break;
                default:
                    break;
            }
        }
    }

    public Session getSession(){
        return session;
    }

    public void setSession(Session session){
        this.session = session;
    }

    // 获取当前所有连接的客户端对象
    public Map<String,Map<String,Session>> getWebSocketSet() {
        return sessionPool;
    }
}